package core

import (
    "context"
    "sync"

    "gitee.com/shijingzhao/z-frame/zhttp"
    "gitee.com/shijingzhao/z-frame/zlog"
    "gitee.com/shijingzhao/z-frame/zrpc"
    "gitee.com/shijingzhao/z-frame/zscript"
)

type App struct {
    name string // 应用名

    ctx    context.Context    // 上下文
    cancel context.CancelFunc // 上下文取消

    wg sync.WaitGroup // 同步等待

    load  func() // 系统加载时执行
    ready func() // 执行后再启动服务

    http    *zhttp.Http
    rpc     *zrpc.Server
    script  *zscript.Script
    crontab string
}

func NewApp() *App {
    // 上下文, 上下文取消
    ctx, cancel := context.WithCancel(context.Background())

    // 前置
    beforeProcess()

    app := &App{
        name:   AppConfig.Name,
        ctx:    ctx,
        cancel: cancel,
        wg:     sync.WaitGroup{},
    }

    return app
}

// 创建应用的前置操作
func beforeProcess() {
    // 读取系统配置
    LoadSystemConfig()
    // 初始化日志句柄
    zlog.NewZLog(AppConfig.Log)
}

// 创建应用的后置操作
func afterProcess() {

}

func (a *App) OnLoad(f func()) {

}

func (a *App) OnReady(f func()) {
    a.ready = f
}

/**
 *[HTTP]
 */

// AddHttpRoutes 添加http路由
func (a *App) AddHttpRoutes(routes []zhttp.Route) {
    if a.http == nil {
        // 注册http服务器
        a.http = zhttp.NewHttp(a.ctx, AppConfig.Http)
    }

    a.http.AddRouter(routes)
}

// AddMiddlewareHttpRoute 添加带中间件的http路由
func (a *App) AddMiddlewareHttpRoute(middlewares []zhttp.Middleware, routes []zhttp.Route) {
    if a.http == nil {
        // 注册http服务器
        a.http = zhttp.NewHttp(a.ctx, AppConfig.Http)
    }

    a.http.AddMiddlewareRoute(middlewares, routes)
}

/**
 *[Script]
 */

// AddScript 添加脚本
func (a *App) AddScript(handlers []zscript.Handler) {
    if a.script == nil {
        // 注册http服务器
        a.script = zscript.NewScript(a.ctx, AppConfig.Script)
    }
    a.script.AddHandle(handlers)
}

/**
 *[Rpc]
 */

// AddRpc 添加RPC
func (a *App) AddRpc(handler []zrpc.Handler) {
    if a.rpc == nil {
        // 注册rpc服务器
        a.rpc = zrpc.NewServer(a.ctx, AppConfig.Rpc)
    }
    a.rpc.AddHandler(handler)
}

// Start 启动应用
func (a *App) Start() {
    if a.ready != nil {
        a.ready()
    }

    if a.http != nil {
        a.http.Start(&a.wg)
    }

    if a.script != nil {
        a.script.Start(&a.wg)
    }

    if a.rpc != nil {
        a.rpc.Start(&a.wg)
    }

    // 后置
    afterProcess()

    a.wg.Wait()
}

// Stop 停止应用
func (a *App) Stop(f func()) {
    a.wg.Add(1)
    fun := func() {
        defer a.wg.Done()

        f()

        // http
        if a.http != nil {
            a.http.ShutDown()
        }

        // rpc
        if a.rpc != nil {
            a.rpc.Close()
        }

        // 取消上下文
        a.cancel()
    }

    registerExitListening(fun)
}
